package com.atguigu.gmall.order.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.filter.IFilterConfig;
import com.atguigu.gmall.cart.pojo.Cart;
import com.atguigu.gmall.cart.pojo.UserInfo;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.common.exception.CartException;
import com.atguigu.gmall.common.exception.OrderException;
import com.atguigu.gmall.oms.api.GmallOmsApi;
import com.atguigu.gmall.order.feign.*;
import com.atguigu.gmall.order.intercepter.LoginIntercepter;
import com.atguigu.gmall.order.vo.OrderConfirmVo;
import com.atguigu.gmall.oms.vo.OrderItemVo;
import com.atguigu.gmall.oms.vo.OrderSubmitVO;
import com.atguigu.gmall.pms.entity.SkuAttrValueEntity;
import com.atguigu.gmall.pms.entity.SkuEntity;
import com.atguigu.gmall.sms.vo.ItemSaleVo;
import com.atguigu.gmall.ums.entity.UserAddressEntity;
import com.atguigu.gmall.ums.entity.UserEntity;
import com.atguigu.gmall.wms.entity.SkuLockVO;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class OrderService {
    @Autowired
    GmallCartClient cartClient;
    @Autowired
    GmallPmsClient pmsClient;
    @Autowired
    GmallSmsClient smsClient;
    @Autowired
    GmallWmsClient wmsClient;
    @Autowired
    GmallUmsClient umsClient;
    @Autowired
    GmallOmsClient omsClient;
    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    RabbitTemplate rabbitTemplate;
    private static final String KEY_PREFIX = "order:token:";
    /**
     * 确认页面
     * @return
     */

    public OrderConfirmVo confirm() {
        //获取用户的信息,此时的用户都是已登录的用户
        UserInfo userInfo = LoginIntercepter.getUserInfo();
        Long userId = userInfo.getUserId();
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        //根据用户的id查询用户的送货地址的相关信息
        ResponseVo<List<UserAddressEntity>> userAddressEntityListResponseVo = umsClient.getUserAddressEntityListById(userId);
        List<UserAddressEntity> userAddressEntityList = userAddressEntityListResponseVo.getData();
        orderConfirmVo.setAddresses(userAddressEntityList);
            //根据当前用户的id查询用户信息（包含积分）
        ResponseVo<UserEntity> userEntityResponseVo = umsClient.queryUserById(userId);
        UserEntity userEntity = userEntityResponseVo.getData();
        if (userEntity!=null){
            orderConfirmVo.setBounds(userEntity.getIntegration());
        }
        //根据用户的id查询购物车中已选择的商品列表
        ResponseVo<List<Cart>> cartInfoResponseVo = cartClient.getCartInfoByUserId(userId);
        List<Cart> carts = cartInfoResponseVo.getData();
        if (CollectionUtils.isEmpty(carts)){
            throw new CartException("您没有要购买的商品");
        }
        //把购物车集合转化成送货清单集合

   orderConfirmVo.setItems(carts.stream().map(cart -> {
            OrderItemVo orderItemVo = new OrderItemVo();
            //cart中仅设置购买的数量及skuId，其他属性一律实时查询
            orderItemVo.setCount(cart.getCount().intValue());
            orderItemVo.setSkuId(cart.getSkuId());
            //查询sku字段相关的信息
       ResponseVo<SkuEntity> skuEntityResponseVo = pmsClient.querySkuById(cart.getSkuId());
       SkuEntity skuEntity = skuEntityResponseVo.getData();
        if (skuEntity!=null){
            orderItemVo.setWeight(new BigDecimal(skuEntity.getWeight()));
            orderItemVo.setTitle(skuEntity.getTitle());
            orderItemVo.setPrice(skuEntity.getPrice());
            orderItemVo.setDefaultImage(skuEntity.getDefaultImage());
        }
        //查询销售属性
       ResponseVo<List<SkuAttrValueEntity>> listResponseVo = pmsClient.querySaleAttrValuesBySkuId(cart.getSkuId());
       orderItemVo.setSaleAttrs(listResponseVo.getData());

       //查询库存
       ResponseVo<List<WareSkuEntity>> wareSkuResponseVo = wmsClient.queryWareSkuBySkuId(cart.getSkuId());
       List<WareSkuEntity> data = wareSkuResponseVo.getData();
        if (!CollectionUtils.isEmpty(data)){
         orderItemVo.setStore(data.stream().anyMatch(t->t.getStock()-t.getStockLocked()>0));
        }
        //查询营销信息
       ResponseVo<List<ItemSaleVo>> itemSaleInfoBySkuId = smsClient.getItemSaleInfoBySkuId(cart.getSkuId());
       orderItemVo.setSales(itemSaleInfoBySkuId.getData());

       return orderItemVo;
        }).collect(Collectors.toList()));
        //设置防重的唯一标识
        String orderToken = IdWorker.getIdStr();
        orderConfirmVo.setOrderToken(orderToken);
            //将防重的唯一表示存入redis缓存中，将来作为数据的唯一性校验
        this.redisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+orderToken,orderToken,5, TimeUnit.MINUTES);

        return orderConfirmVo;
    }

    //订单提交至支付页面
    public void submit(OrderSubmitVO orderSubmitVO) {
        //1、防重，页面上的orderToken与redis中的比较，
        // 如果有，说明没有重复提交，验证完立刻删除
        String orderToken = orderSubmitVO.getOrderToken();
        String token = this.redisTemplate.opsForValue().get(KEY_PREFIX+orderToken);
        if (StringUtils.isBlank(token)){
            throw new OrderException("非法请求！");
        }

        //如果token存在则进行删除，此时需要保证操作的原子性
        String script = "if redis.call('GET',KEYS[1])==ARGV[1] " +
                "then return redis.call('DEL',KEYS[1]) " +
                "else return 0 end";
        Boolean result = this.redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList(KEY_PREFIX+orderToken), token);
        if (!result){
            throw new OrderException("请勿重复提交订单");
        }
        //2、校验总价
        BigDecimal totalPrice = orderSubmitVO.getTotalPrice();
        //确认实时价格
        List<OrderItemVo> items = orderSubmitVO.getItems();
        if (CollectionUtils.isEmpty(items)){
            throw new OrderException("你没有要购买的商品");
        }
        BigDecimal currentPrice = items.stream().map(item -> {
            ResponseVo<SkuEntity> skuEntityResponseVo = this.pmsClient.querySkuById(item.getSkuId());
            SkuEntity skuEntity = skuEntityResponseVo.getData();
            if (skuEntity == null) {
                return new BigDecimal(0);
            }
            return skuEntity.getPrice();
        }).reduce((a, b) -> a.add(b)).get();

        if (totalPrice.compareTo(currentPrice)!=0){
            throw  new OrderException("页面已过期，请刷新后重试！");
        }

        //todo 限制购买数量

        //3、锁库存
        List<SkuLockVO> skuLockVos = items.stream().map(item -> {
            SkuLockVO skuLockVO = new SkuLockVO();
            skuLockVO.setSkuId(item.getSkuId());
            skuLockVO.setCount(item.getCount());
            return skuLockVO;
        }).collect(Collectors.toList());

        ResponseVo<List<SkuLockVO>> listResponseVo = this.wmsClient.checkAndLock(skuLockVos, orderToken);
        List<SkuLockVO> skuLockVOList = listResponseVo.getData();
        if (!CollectionUtils.isEmpty(skuLockVOList)){
            throw  new OrderException(JSON.toJSONString(skuLockVOList));
        }

        //4、创建订单
        UserInfo userInfo = null;
        try {
          userInfo = LoginIntercepter.getUserInfo();
            ResponseVo responseVo = omsClient.saveOrder(orderSubmitVO, userInfo.getUserId().toString());
            //定时关单
            this.rabbitTemplate.convertAndSend("ORDER_CREATE_EXCHANGE","ttl.order",orderToken);
//            int i = 1/0;

        } catch (Exception e) {
            e.printStackTrace();
            //发送消息给wms解锁库存
            this.rabbitTemplate.convertAndSend("ORDER_CREATE_EXCHANGE","wms.unlock",orderToken);
            //发送消息给oms标记为无效订单
            this.rabbitTemplate.convertAndSend("ORDER_CREATE_EXCHANGE","oms.useless",orderToken);
            throw new OrderException("服务器内部错误");
        }

        //5、删除购物车中的记录,异步删除MQ
        List<Long> skuIds = items.stream().map(OrderItemVo::getSkuId).collect(Collectors.toList());
        Map<String, Object> msg = new HashMap<>();
        msg.put("userId",userInfo.getUserId().toString());
        msg.put("skuIds",JSON.toJSONString(skuIds));
        this.rabbitTemplate.convertAndSend("ORDER_CREATE_EXCHANGE","create_order",msg);

    }
}
